/**
 * Copyright (C) 2009 Olafur Gauti Gudmundsson, Hjortur Stefan Olafsson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.gwt_control.client;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Olafur Gauti Gudmundsson
 */
public class ViewLinkToken implements Serializable {

    private static final String KEY = "view";

    private String viewId;
    private Map<String,String> parameters;
    
    public ViewLinkToken() {}
    
    public ViewLinkToken( String viewId, Map<String,String> parameters ) {
        this.viewId = viewId;
        this.parameters = parameters;
    }
    
    public ViewLinkToken( String viewId ) {
        this(viewId, new HashMap<String,String>());
    }

    public String getViewId() {
        return viewId;
    }

    public void setViewId(String viewId) {
        this.viewId = viewId;
    }

    public Map<String,String> getParameters() {
        return parameters;
    }
    
    public String getParameter( String name ) {
        return parameters.get(name);
    }
    
    public void addParameter( String name, String value ) {
        if ( KEY.equals(name) ) {
            throw new RuntimeException("Cannot add deep link parameter: The name '" + KEY + "' is reserved.");
        }
        parameters.put(name, value);
    }

    public void setParameters(Map<String,String> parameters) {
        for ( String name : parameters.keySet() ) {
            if ( KEY.equals(name) ) {
                throw new RuntimeException("Cannot add deep link parameter: The name '" + KEY + "' is reserved.");
            }
        }
        this.parameters = parameters;
    }
    
    public String encode() {
        StringBuilder buffer = new StringBuilder();
        buffer.append(KEY);
        buffer.append('=');
        buffer.append(viewId);
        for ( Map.Entry<String,String> entry : parameters.entrySet() ) {
            buffer.append('&');
            buffer.append(entry.getKey());
            buffer.append('=');
            if ( entry.getValue() != null ) {
                buffer.append(entry.getValue());
            }
        }
        return encode64(buffer.toString());
    }
    
    public static ViewLinkToken decode( String input ) {
        String data = decode64(input);
        Map<String,String> params = new HashMap<String,String>();
        String[] pairs = data.split("&");
        for ( String pair : pairs ) {
            String[] parts = pair.split("=");
            if ( parts.length > 1 ) {
                params.put(parts[0], parts[1]);
            }
        }
        String viewId = params.get(KEY);
        params.remove(KEY);
        return new ViewLinkToken(viewId, params);
    }

    @Override
    public String toString() {
        return encode();
    }

    public static native String encode64(String input) /*-{
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        do {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
        } while (i < input.length);

        return output;
    }-*/;

    public static native String decode64(String input) /*-{
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        do {
            enc1 = keyStr.indexOf(input.charAt(i++));
            enc2 = keyStr.indexOf(input.charAt(i++));
            enc3 = keyStr.indexOf(input.charAt(i++));
            enc4 = keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }
        } while (i < input.length);

        return output;
    }-*/;
}
